package com.shengqin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shengqin.common.pojo.CommonPage;
import com.shengqin.entity.*;
import com.shengqin.mapper.PlanFreeTestMapper;
import com.shengqin.service.IPlanFreeTestService;
import com.shengqin.service.IPlanStudentService;
import com.shengqin.service.ISchoolService;
import com.shengqin.service.ITestResultService;
import com.shengqin.utils.GradeUtil;
import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.functions.Consumer;
import io.reactivex.rxjava3.schedulers.Schedulers;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.BeanUtils;
import org.springframework.cglib.core.Local;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Service
@Slf4j
public class PlanFreeTestServiceImpl extends ServiceImpl<PlanFreeTestMapper, PlanFreeTest> implements IPlanFreeTestService {

    @Resource
    private IPlanStudentService planStudentService;
    @Resource
    private ITestResultService testResultService;
    @Resource
    private ISchoolService schoolService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importBatchFreeTest(List<PlanFreeTest> cachedDataList, Integer planId) {
        List<String> studyCodes = new ArrayList<>();
        cachedDataList.forEach(planFreeTest -> studyCodes.add(planFreeTest.getStudyCode()));
        List<PlanStudent> planStudents = planStudentService.queryByPlanIdAndStudyCodes(planId, studyCodes);
        Map<String, PlanStudent> planStudentMap = planStudents.stream().collect(Collectors.toMap(PlanStudent::getStudyCode, p -> p));
        List<TestResult> testResults = new ArrayList<>();
        cachedDataList.forEach(planFreeTest -> {
            PlanStudent student = planStudentMap.getOrDefault(planFreeTest.getStudyCode(), null);
            if (student != null) {
                planFreeTest.setPlanId(planId);
                planFreeTest.setName(student.getName());
                planFreeTest.setSchoolId(student.getSchoolId());
                planFreeTest.setGradeId(student.getGradeId().toString());
                planFreeTest.setClassesName(student.getClassesName());
                planFreeTest.setGradeName(GradeUtil.getGradeName(student.getGradeId()));
                planFreeTest.setScore(new BigDecimal(planFreeTest.getScoreText()));
                planFreeTest.setSex(student.getSex());
                planFreeTest.setCreateTime(LocalDateTime.now());


                TestResult testResult = new TestResult();
                BeanUtils.copyProperties(student, testResult);
                testResult.setResult(null);
                testResult.setResultType(planFreeTest.getReason());
                testResult.setPlanId(planId);
                testResult.setPrjName(planFreeTest.getProjectName());
                testResult.setSex(student.getSex());
                testResult.setStudyCode(planFreeTest.getStudyCode());
                testResult.setFinalScore(planFreeTest.getScore());
                testResult.setScore(planFreeTest.getScore());
                testResult.setGradeId(Integer.parseInt(planFreeTest.getGradeId()));
                testResult.setCreateTime(LocalDateTime.now());
                testResults.add(testResult);
            }
        });
        saveOrUpdateBatch(cachedDataList);
        Map<String, List<TestResult>> testResultMap = testResults.stream().collect(Collectors.groupingBy(TestResult::getStudyCode));
        testResultMap.forEach((studyCode, testResultList) -> CompletableFuture.runAsync(() -> {
            try {
                log.info("开始操作免考{},{}", studyCode, testResultList.size());
                if (!CollectionUtils.isEmpty(testResultList)) {
                    Set<String> prjNames = testResultList.stream().map(TestResult::getPrjName).collect(Collectors.toSet());
                    testResultService.removeByPlanIdAndStudyCodeAndPrjNames(planId, studyCode, prjNames);
                    testResultService.saveOrUpdateBatch(testResultList);
                }
                TestResult query = new TestResult();
                query.setPlanId(planId);
                query.setStudyCode(studyCode);
                testResultService.calculate(query);
                log.info("操作免考结束{}", studyCode);
            } catch (Exception e) {
                log.error("操作免考失败{},{}", studyCode, e.getMessage());
            }
        }));
    }

    @Override
    public List<PlanFreeTest> queryByPlanIdAndStudyCodes(Integer planId, Set<String> studyCodes) {
        QueryWrapper<PlanFreeTest> wrapper = new QueryWrapper<>();
        wrapper.lambda().in(PlanFreeTest::getStudyCode, studyCodes);
        wrapper.lambda().eq(PlanFreeTest::getPlanId, planId);
        return list(wrapper);
    }

    @Override
    public Page<PlanFreeTest> queryPage(CommonPage<PlanFreeTest> commonPage) {
        PlanFreeTest queryParam = commonPage.getQueryParam();
        QueryWrapper<PlanFreeTest> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(PlanFreeTest::getPlanId, queryParam.getPlanId());
        if (StringUtils.hasLength(queryParam.getName())) {
            wrapper.lambda().eq(PlanFreeTest::getName, queryParam.getName());
        }
        if (StringUtils.hasLength(queryParam.getStudyCode())) {
            wrapper.lambda().eq(PlanFreeTest::getStudyCode, queryParam.getStudyCode());
        }
        if (StringUtils.hasLength(queryParam.getGradeId())) {
            wrapper.lambda().eq(PlanFreeTest::getGradeId, queryParam.getGradeId());
        }
        if (queryParam.getSchoolId() != null) {
            wrapper.lambda().eq(PlanFreeTest::getSchoolId, queryParam.getSchoolId());
        }
        wrapper.lambda().orderByDesc(PlanFreeTest::getId);
        Page<PlanFreeTest> freeTestPage = new Page<>(commonPage.getPageNo(), commonPage.getPageSize());
        page(freeTestPage, wrapper);
        buildRecords(freeTestPage.getRecords());
        return freeTestPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean refresh(PlanFreeTest queryParam) {
        QueryWrapper<PlanFreeTest> wrapper = new QueryWrapper<>();
        if (queryParam.getPlanId() != null) {
            wrapper.lambda().eq(PlanFreeTest::getPlanId, queryParam.getPlanId());
        }
        if (StringUtils.hasLength(queryParam.getName())) {
            wrapper.lambda().eq(PlanFreeTest::getName, queryParam.getName());
        }
        if (StringUtils.hasLength(queryParam.getStudyCode())) {
            wrapper.lambda().eq(PlanFreeTest::getStudyCode, queryParam.getStudyCode());
        }
        if (StringUtils.hasLength(queryParam.getGradeId())) {
            wrapper.lambda().eq(PlanFreeTest::getGradeId, queryParam.getGradeId());
        }
        if (queryParam.getSchoolId() != null) {
            wrapper.lambda().eq(PlanFreeTest::getSchoolId, queryParam.getSchoolId());
        }
        List<PlanFreeTest> planFreeTests = list(wrapper);

        Map<Integer, List<PlanFreeTest>> planFreeTestsMap = planFreeTests.stream().collect(Collectors.groupingBy(PlanFreeTest::getPlanId));

        planFreeTestsMap.forEach((planId, planFreeTestList) -> {
            List<String> studyCodes = new ArrayList<>();
            planFreeTestList.forEach(planFreeTest -> studyCodes.add(planFreeTest.getStudyCode()));
            List<PlanStudent> planStudents = planStudentService.queryByPlanIdAndStudyCodes(planId, studyCodes);
            Map<String, PlanStudent> planStudentMap = planStudents.stream().collect(Collectors.toMap(PlanStudent::getStudyCode, p -> p));

            List<TestResult> testResults = new ArrayList<>();

            planFreeTestList.forEach(planFreeTest -> {
                PlanStudent student = planStudentMap.getOrDefault(planFreeTest.getStudyCode(), null);
                if (student != null) {
                    TestResult testResult = new TestResult();
                    BeanUtils.copyProperties(student, testResult);
                    testResult.setResult(null);
                    testResult.setResultType(planFreeTest.getReason());
                    testResult.setPlanId(planFreeTest.getPlanId());
                    testResult.setPrjName(planFreeTest.getProjectName());
                    testResult.setStudyCode(planFreeTest.getStudyCode());
                    testResult.setFinalScore(planFreeTest.getScore());
                    testResult.setScore(planFreeTest.getScore());
                    testResult.setGradeId(Integer.parseInt(planFreeTest.getGradeId()));
                    testResults.add(testResult);
                }
            });

            Map<String, List<TestResult>> testResultMap = testResults.stream().collect(Collectors.groupingBy(TestResult::getStudyCode));
            testResultMap.forEach((studyCode, testResultList) -> {
                Set<String> prjNames = testResultList.stream().map(TestResult::getPrjName).collect(Collectors.toSet());
                testResultService.removeByPlanIdAndStudyCodeAndPrjNames(planId, studyCode, prjNames);
                testResultService.saveOrUpdateBatch(testResults);
                TestResult query = new TestResult();
                query.setPlanId(planId);
                query.setStudyCode(studyCode);
                testResultService.calculate(query);
            });
        });

        return true;
    }

    @Override
    public List<PlanFreeTest> listByPlanIdAndStudyCode(Integer planId, String studyCode) {
        QueryWrapper<PlanFreeTest> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(PlanFreeTest::getPlanId, planId);
        wrapper.lambda().eq(PlanFreeTest::getStudyCode, studyCode);
        return list(wrapper);
    }

    @Override
    public void deleteByPlanIdAndStudyCode(Integer planId, String studyCode) {
        QueryWrapper<PlanFreeTest> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(PlanFreeTest::getPlanId, planId);
        wrapper.lambda().eq(PlanFreeTest::getStudyCode, studyCode);
        remove(wrapper);
    }

    private void buildRecords(List<PlanFreeTest> records) {
        if(!CollectionUtils.isEmpty(records)){
            Set<Integer> schoolIds = new HashSet<>();
            records.forEach(item -> {
                schoolIds.add(item.getSchoolId());
                item.setGradeName(GradeUtil.getGradeName(Integer.valueOf(item.getGradeId())));
            });
            if(!CollectionUtils.isEmpty(schoolIds)){
                List<School> schoolList = schoolService.listByIds(schoolIds);
                records.forEach(item -> {
                    schoolList.forEach(school -> {
                        if(item.getSchoolId().equals(school.getId())){
                            item.setSchoolName(school.getName());
                        }
                    });
                });
            }
        }
    }
}
